home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NOVA - For the NeXT Workstation
/
NOVA - For the NeXT Workstation.iso
/
Apps
/
Graphics
/
Viewers
/
ViewGif2
/
DecodeGIF.m
< prev
next >
Wrap
Text File
|
1992-12-25
|
15KB
|
419 lines
/*****************************************************************************/
/* DecodeGIF.m */
/* implementation file of DecodeGIF class of ViewGif2 application */
/* Handles decoding of GIF files, and decoding status panel */
/* January 1990 Carl F. Sutter */
/*****************************************************************************/
#import "DecodeGIF.h"
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/Control.h>
#import <appkit/Panel.h>
#import <appkit/Slider.h> // for setMinValue, setMaxValue
#import <appkit/tiff.h> // for NXImageBitmap
#import <stdlib.h> // for malloc and free
#import <stdio.h> // for fprintf
#import <string.h> // for strcpy
/* some external function references to do the actual LZW decoding */
void StartLZW( BYTE byCodeSizeIn, NXStream *stream,
BYTE *byR, BYTE *byG, BYTE *byB, BYTE *byMap,
int width, int height, BOOL bInter );
long ContinueLZW( int nNumCodes );
@implementation DecodeGIF
/*****************************************************************************/
/* new - factory method */
/*****************************************************************************/
+ new
{
self = [super new];
[self setup];
return( self );
} /* new 1/22/90 CFS */
/*****************************************************************************/
/* new - factory method with target and action */
/*****************************************************************************/
+ new:(id )targ action:(SEL )act
{
self = [super new];
[self setup];
target = targ;
action = act;
return( self );
} /* new:action: 1/23/90 CFS */
/*****************************************************************************/
/* setup - initialize instance variables and panel etc. */
/*****************************************************************************/
- setup
{
/* load nib defining panel and outlets */
[NXApp loadNibSection:"DecodeGIF.nib" owner:self];
bDecoding = NO;
return( self );
} /* setup 1/23/90 CFS */
/*****************************************************************************/
/* outlet initialization methods */
/*****************************************************************************/
- setDecodePanel:anObject { decodePanel = anObject; return( self ); }
- setGauge:anObject { gauge = anObject; return( self ); }
- setWidth:anObject { width = anObject; return( self ); }
- setHeight:anObject { height = anObject; return( self ); }
- setNumColors:anObject { numColors = anObject; return( self ); }
- setFilename:anObject { filename = anObject; return( self ); }
/*****************************************************************************/
/* show - display the decoder panel */
/*****************************************************************************/
- show:sender
{
[decodePanel makeKeyAndOrderFront:self];
return( self );
} /* show 1/23/90 CFS */
/*****************************************************************************/
/* setTarget - sets the object to return queue items to */
/*****************************************************************************/
- setTarget:(id)targ
{
target = targ;
return( self );
} /* setTarget 1/22/90 CFS */
/*****************************************************************************/
/* setAction - sets the method that will be called with the new item */
/* there will be one parameter - a pointer to a standard C string */
/*****************************************************************************/
- setAction:(SEL)aSelector
{
action = aSelector;
return( self );
} /* setAction 1/22/90 CFS */
/*****************************************************************************/
/* decodeFile - called from controller to initiate decoding process */
/*****************************************************************************/
- decodeFile:(const char *)fileName
{
strcpy( szPathName, fileName );
strcpy( szFileName, strrchr( fileName, '/' ) + 1);
[filename setStringValue:szFileName];
nStatus = STATUS_OPEN;
/* use the timer to break up the decoding process and allow other events */
timer = [[Animator alloc] initChronon:0.0 adaptation:0.0 target:self
action:@selector(nextStep:) autoStart:YES
eventMask:NX_ALLEVENTS];
return( self );
} /* decodeFile 1/23/90 CFS */
/*****************************************************************************/
/* nextStep - called by timer, parse control to current task */
/*****************************************************************************/
- nextStep:sender
{
#define CODES_PER_ITERATION 300
long lReturn;
/* first, go right to the decoder, if LZW decoding is in progress */
if (bDecoding)
{
lReturn = ContinueLZW( CODES_PER_ITERATION );
if ((lReturn == 0) || (lReturn == -1)) [self finishDecoder:lReturn];
else [gauge setFloatValue:(float)lReturn];
}
/* otherwise, go to the proper step in the rest of the decoding process */
else switch (nStatus)
{
case STATUS_OPEN: [self openFile]; break;
case STATUS_GLOBAL: [self readGlobalInfo]; break;
case STATUS_BLOCK: [self readBlockCode]; break;
case STATUS_IMAGE: [self readImageInfo]; break;
case STATUS_DECODING: [self startDecoder]; break;
case STATUS_EXTENSION: [self cancelDecoding]; break; // FIX THIS
case STATUS_DONE: [self sucessfulDecoding]; break; // ALLOW MULT IMAGES
}
return( self );
} /* nextStep 1/23/90 CFS */
/*****************************************************************************/
/* openFile - open the stream for decoding */
/*****************************************************************************/
- (BOOL)openFile
{
if (!(stream = NXMapFile( szPathName, NX_READONLY )))
{
[self errorAlert:"Could not open GIF file."];
[self cancelDecoding];
return( NO );
}
nStatus = STATUS_GLOBAL;
return( YES );
} /* openFile 1/23/90 CFS */
/***************************************************************************/
/* readGlobalInfo - read the global header from the file */
/***************************************************************************/
- (BOOL)readGlobalInfo
{
BYTE b1, b2;
char szSignature[7];
struct {
unsigned map:1;
unsigned res:3;
unsigned reserved:1;
unsigned bpp:3;
} globalInfo;
/* read 6 byte version signature */
if (![self readBytes:6 data:szSignature]) return( NO );
szSignature[6] = 0;
if (0 != strcmp( szSignature, "GIF87a"))
{
[self errorAlert:"Not a GIF file - signature not GIF87a."];
[self cancelDecoding];
return( NO );
}
/* read screen width and height */
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
/* read info byte */
if (![self readBytes:1 data:&globalInfo]) return( NO );
// GlobalInfo.nResolution = globalInfo.res + 1;
nBPP = globalInfo.bpp + 1;
/* read background color */
if (![self readBytes:1 data:&b1]) return( NO );
// GlobalInfo.nBackground = b1;
/* reserved zero at end of screen descriptor */
if (![self readBytes:1 data:&b1]) return( NO );
/* read in the global color map, if it exists */
if (globalInfo.map) [self readMap];
/* everything loaded OK, return TRUE */
nStatus = STATUS_BLOCK;
return( YES );
} /* readGlobalInfo 10/16/89 CFS */
/***************************************************************************/
/* readMap - read a color map from the stream */
/***************************************************************************/
- (BOOL)readMap
{
nNumColors = 1;
nNumColors <<= nBPP; /*2^BPP*/
[numColors setIntValue:nNumColors];
if (![self readBytes:nNumColors * 3 data:byColorMap]) return( NO );
return( YES );
} /* readMap 1/23/90 CFS */
/***************************************************************************/
/* readBlockCode - read the next character blockcode and set status */
/***************************************************************************/
- (BOOL)readBlockCode
{
char cBlockCode;
if (![self readBytes:1 data:&cBlockCode]) return( NO );
switch (cBlockCode)
{
case ',': nStatus = STATUS_IMAGE; break;
case '!': nStatus = STATUS_EXTENSION; break;
case ';': nStatus = STATUS_DONE; break;
default:
{
[self errorAlert:"Bad block code in readNextBlockCode."];
[self cancelDecoding];
return( NO );
}
}
return( YES );
} /* readBlockCode 1/23/90 CFS */
/***************************************************************************/
/* readImageInfo - read the image information header from the file */
/***************************************************************************/
- (BOOL)readImageInfo
{
BYTE b1, b2;
struct {
unsigned map:1;
unsigned interlace:1;
unsigned reserved:3;
unsigned bpp:3;
} localInfo;
/* read the image margins and size */
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
// ImageInfo.nLeftMargin = b2 * 256 + b1;
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
// ImageInfo.nTopMargin = b2 * 256 + b1;
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
nWidth = b2 * 256 + b1;
[width setIntValue:nWidth];
if (![self readBytes:1 data:&b1]) return( NO );
if (![self readBytes:1 data:&b2]) return( NO );
nHeight = b2 * 256 + b1;
[height setIntValue:nHeight];
/* read the image info byte */
if (![self readBytes:1 data:&localInfo]) return( NO );
bInterlaced = localInfo.interlace;
// ImageInfo.nBPP = localInfo.bpp + 1;
if (localInfo.map) [self readMap];
/* everything loaded OK, return TRUE */
nStatus = STATUS_DECODING;
return( YES );
} /* readImageInfo 10/16/89 CFS */
/***************************************************************************/
/* startDecoder - control decoding of the image */
/***************************************************************************/
- (BOOL)startDecoder
{
BYTE byCodeSize;
[decodePanel setTitle:"Decoding Status - decoding..."];
/* read the beginning code size - should be same as BPP */
if (![self readBytes:1 data:&byCodeSize]) return( NO );
/* free any previous image data & allocate space for the current image */
free( byDataR );
free( byDataG );
free( byDataB );
byDataR = malloc( nWidth * nHeight );
byDataG = malloc( nWidth * nHeight );
byDataB = malloc( nWidth * nHeight );
/* set up the time left gauge */
[gauge setMinValue:0];
[gauge setMaxValue:nHeight * nWidth];
[gauge setIntValue:0];
/* start the LZW decoder */
StartLZW( byCodeSize, stream, byDataR, byDataG, byDataB, byColorMap,
nWidth, nHeight, bInterlaced );
bDecoding = YES;
return( YES );
} /* startDecoder 1/24/90 CFS */
/***************************************************************************/
/* finishDecoder: - clean up after the LZW process */
/***************************************************************************/
- (BOOL)finishDecoder:(long)lReturnCode
{
NXRect nxrBit;
if (lReturnCode == -1) [self errorAlert:
"The whole image couldn't be loaded.\nAs much as possible will be shown."];
[gauge setFloatValue:(float)(nWidth * nHeight)];
/* create a bitmap, and image the data into it */
[decodePanel setTitle:"Decoding Status - imaging..."];
nxrBit.size.width = nWidth;
nxrBit.size.height = nHeight;
bmpOut = [Bitmap newSize:nxrBit.size.width :nxrBit.size.height
type:NX_UNIQUEBITMAP];
[bmpOut setFlip:NO];
[bmpOut lockFocus];
NXImageBitmap( &nxrBit, nWidth, nHeight, 8, 3, NX_PLANAR,
NX_COLORMASK, byDataR, byDataG, byDataB, NULL, NULL );
[bmpOut unlockFocus];
[decodePanel setTitle:"Decoding Status"];
bDecoding = NO;
nStatus = STATUS_DONE;
// ALLOW MULTIPLE IMAGES EVENTUALLY
// /* read the last block count - should be zero */
// if (![self readBytes:1 data:&byDummy]) return( NO );
// nStatus = STATUS_BLOCK;
return( YES );
} /* finishDecoder: 1/24/90 CFS */
/***************************************************************************/
/* sucessfulDecoding - send decoded image to controller */
/***************************************************************************/
- sucessfulDecoding
{
[timer free];
NXCloseMemory( stream, NX_FREEBUFFER );
[target perform:action with:bmpOut];
return( self );
} /* sucessfulDecoding 1/23/90 CFS */
/***************************************************************************/
/* cancelDecoding - notify controller that file couldn't be decoded */
/***************************************************************************/
- cancelDecoding
{
[timer free];
NXCloseMemory( stream, NX_FREEBUFFER );
[target perform:action with:nil with:(id)NO];
return( self );
} /* cancelDecoding 1/23/90 CFS */
/***************************************************************************/
/* readBytes - read in the desired number of data bytes */
/***************************************************************************/
- (BOOL)readBytes:(int)nNumBytes data:(void *)buf
{
int nError;
nError = NXRead( stream, buf, nNumBytes );
if (nError <= 0)
{
[self errorAlert:"File couldn't be completely read."];
[self cancelDecoding];
return( NO );
}
return( YES );
} /* readBytes 1/23/90 CFS */
/***************************************************************************/
/* errorAlert - put the message in an alert panel */
/***************************************************************************/
- errorAlert:(char *)szMessage
{
NXRunAlertPanel( "ViewGif2 Error", szMessage, "OK", NULL, NULL );
return( self );
} /* errorAlert 10/30/89 CFS */
@end